package org.lib.jpamysql.query;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.stream.Stream;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;
import org.springframework.util.concurrent.ListenableFuture;

/**
 * 定义查询方法：根据方法名创建（关键字）
 * @author ben
 * @date 2021-10-30 09:21:46 CST
 */
@Repository(value = "userDao")
public interface UserDAO extends JpaRepository<User, Long> {

	// 创建查询方法 by 查询生成器机制
	// find by, read by, query by, count by, get by

	List<User> findByFirstName(String firstName);
	
	List<User> findByLastName(String lastName);
	
	// And
	List<User> findByFirstNameAndLastName(String firstName, String lastName);
	
	List<User> findByFirstNameAndAge(String firstName, int age);

	// Or
	List<User> findByFirstNameOrLastName(String firstName, String lastName);
	
	// Distinct 去重
	// 无效 因为创建时间等不一样？
	List<User> findDistinctByFirstName(String firstName);

	// IgnoreCase 忽略大小写
	// 无效 数据库不支持？
	List<User> findByFirstNameIgnoreCase(String firstName);

	// ASC/DESC 排序
	List<User> findByFirstNameOrderByAgeDesc(String firstName);
	
	// 更多查询
	
	// Between
	List<User> findByAgeBetween(int age1, int age2);

	// GreaterThan
	List<User> findByAgeGreaterThan(int min);

	// After Date类型
	List<User> findByCreateTimeAfter(Date start);
	
	// Like
	List<User> findByFirstNameLike(String pattern);

	// Containing
	List<User> findByFirstNameContaining(String keywords);
	
	// 方法的查询策略的属性表达式
	List<User> findByAddressZipCode(String zipCode);
	
	// IsNull
	List<User> findByAddressZipCodeIsNull();
	
	// NotNull or IsNotNull
	List<User> findByAddressZipCodeNotNull();
	
	// 返回Page、Slice
	// 下面两个findByAgeBetween不能同时存在
	
//	Page<User> findByAgeBetween(int age1, int age2, Pageable pageable);
	
	Slice<User> findByAgeBetween(int age1, int age2, Pageable pageable);
	
	// 使用first, top
	
	User findFirstByFirstName(String firstName);
	
	User findTopByFirstName(String firstName);
	
	List<User> findFirst2ByFirstName(String firstName);

	// 返回Stream
	
	@Query("select u from User u")
	Stream<User> findAllByCustomQueryAndStream();
	
	// 异步查询结果
	
	// findOne 查询到多个结果时，发生异常：javax.persistence.NonUniqueResultException
	@Async
	Future<User> findOneByAge(int age);
	
	// findOne 查询到多个结果时，发生异常：javax.persistence.NonUniqueResultException
	@Async
	CompletableFuture<User> findOneByFirstName(String firstName);
	
	// findOne 查询到多个结果时，发生异常：javax.persistence.NonUniqueResultException
	@Async
	ListenableFuture<User> findOneByLastName(String lastName);
	
	// projections
	
//	List<NameOnly> findByLastName(String lastName);
	
}
